FIX: Add /ship skill for branch, atomic commits, and draft PR workflow#76
FIX: Add /ship skill for branch, atomic commits, and draft PR workflow#76tahierhussain wants to merge 6 commits intomainfrom
Conversation
Adds a manual-only Claude Code skill that walks uncommitted changes through branch creation, atomic commits, push, and draft PR. Includes the project's PR body template as the source of truth for PR descriptions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| Filename | Overview |
|---|---|
| .claude/skills/ship/SKILL.md | Comprehensive skill definition with well-structured phases, confirmation gates, and secrets scanning; all previously flagged P1 issues resolved; two minor P2 items remain (xargs -r portability and hardcoded model version in Co-Authored-By trailer). |
| .claude/skills/ship/pr-body-template.md | Clean PR body template matching the project's required sections; no issues found. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A(["/ship invoked"]) --> B[Phase 1: Discover & Classify\ngit status / diff HEAD / ls-files]
B --> C{Changes?}
C -- "None on main/master/develop" --> Z1([Stop: no changes])
C -- "Already committed" --> SEC1[Secrets scan\ngit diff base...HEAD]
C -- "Uncommitted" --> SEC2[Secrets scan\ngit diff HEAD + untracked files]
SEC1 --> SEC_GATE{Hit?}
SEC2 --> SEC_GATE
SEC_GATE -- "Yes" --> AUQ[AskUserQuestion:\nDrop / Remove / Cancel]
AUQ --> Z2([Stop or continue clean])
SEC_GATE -- "No" --> D{feat / fix / mixed?}
D -- "Mixed" --> GATE0[Gate 0: split PRs?]
D -- "Clear" --> E[Phase 2: Plan branch name\nfeat/ or fix/]
GATE0 --> E
E --> F[Phase 3: Plan atomic commits]
F --> GATE1{Gate 1: confirm plan?}
GATE1 -- "No" --> Z3([Abort])
GATE1 -- "Yes" --> G[Phase 4: Execute\ngit checkout -b\ngit add + commit x N\ngit push -u origin]
G --> H[Phase 5: Draft PR body\nread pr-body-template.md]
H --> GATE2{Gate 2: confirm body?}
GATE2 -- "No" --> Z4([Abort])
GATE2 -- "Yes" --> I[Phase 6: Raise PR\ngh auth check\ncheck existing PR\nsanitize branch name\nwrite /tmp body\ngh pr create --draft\nclean up temp file]
I --> J([Print PR URL])
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
.claude/skills/ship/SKILL.md:108-113
`xargs -r` (`--no-run-if-empty`) is a GNU coreutils extension — it does not exist in macOS's BSD `xargs`. When there are no untracked files, the empty-input pipeline on macOS causes `xargs` to exit with a "illegal option" error (exit code non-zero). With `2>/dev/null` suppressing the message but not the exit code, Claude's Bash tool would see a failure here and may abort the workflow or silently skip the untracked-file scan, defeating the hard-stop guarantee. Replacing `-r` with an explicit emptiness guard is portable across macOS and Linux.
```suggestion
A combined invocation:
```bash
git diff HEAD | grep -E '<patterns>'
UNTRACKED=$(git ls-files --others --exclude-standard 2>/dev/null)
[ -n "$UNTRACKED" ] && echo "$UNTRACKED" | xargs grep -EIn '<patterns>' 2>/dev/null || true
```
```
### Issue 2 of 2
.claude/skills/ship/SKILL.md:31-32
The `Co-Authored-By` trailer hard-codes `Claude Opus 4.7 (1M context)`, which will become stale as soon as a newer model handles this skill. Every commit made from this skill at that point carries an inaccurate attribution. Consider using a version-agnostic label (e.g., `Claude Code`) so the trailer remains accurate indefinitely without needing edits to this file.
```suggestion
**Commit trailer:** Every commit message ends with the trailer
`Co-Authored-By: Claude Code <noreply@anthropic.com>`,
```
Reviews (6): Last reviewed commit: "fix(claude): scan untracked files in /sh..." | Re-trigger Greptile
…n /ship skill - Fix line-continuation bug in the Phase 6 gh pr create example: move the FEAT/FIX note above the block so every flag carries a backslash. - Resolve --base dynamically via `gh repo view` so the skill works on repos whose default branch is not `main`. - Add `AskUserQuestion` to allowed-tools so the secrets-scan hard-stop can present its structured three-option prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Branch names always contain a `/` (feat/<kebab> or fix/<kebab>), so `/tmp/pr-body-<branch>.md` resolved to a non-existent subdirectory and broke the write, --body-file, and cleanup steps. Sanitize via `tr '/' '-'` into `$BRANCH_SAFE` and thread it through all three. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop unused Edit from allowed-tools. - Document the Co-Authored-By trailer in commit-format conventions. - Tighten the AWS secret-key scan to assignment + 40-char value so bare references in .env.example don't trip the gate. - Reorder Phase 6 so gh auth status runs before any temp-file write, add an existing-PR check that stops with the URL surfaced (no silent gh pr create failure on re-runs), make the title prefix derive from classification instead of hard-coded FEAT, and switch cleanup to rm -f. - Require every '-' placeholder from the PR-body template to be replaced with prose or a literal TODO before raising. - Update Section 9 to describe the existing-PR stop behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Edge case "no uncommitted changes" previously said to skip Phases 1-4 wholesale, which silently bypassed the secrets-scan hard stop in Phase 1 and contradicted the Section 8 guardrail. Now the scan still runs against `git diff <base>...HEAD` on this path; only the commit-planning steps (Phases 2-3) are skipped if the scan comes back clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`git diff HEAD` only covers tracked files — net-new files (those with `??` in `git status`, never `git add`-ed) were invisible to the secrets scan, so a brand-new `secrets.py` containing `sk-…` could be planned in Phase 3, staged in Phase 4, and committed without ever hitting the hard stop. Phase 1 now lists untracked files via `git ls-files --others --exclude-standard` and scans them in full as a second surface alongside the tracked diff. The hit-handling AskUserQuestion options are extended with untracked-file equivalents (don't `git add` instead of `git restore --staged`; plain `rm` instead of `git rm`). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
What
Adds a new manual-only Claude Code skill at
.claude/skills/ship/thatwalks uncommitted (or already-committed) changes through a structured
flow: branch creation → atomic Conventional-Commits → push → draft PR.
The skill is composed of
SKILL.md(the procedure) andpr-body-template.md(the source-of-truth PR description template).Why
Standardises how PRs get raised from this working directory so branch
names, commit grouping, and PR descriptions stay consistent across
sessions, without relying on memory or ad-hoc prompting. Manual-only
(
disable-model-invocation: true) so it never auto-fires fromconversational pattern-matching — it only runs when explicitly
invoked via
/ship.How
Two new files under
.claude/skills/ship/:SKILL.mddefines six phases (discover/classify, plan branch name,plan commits with confirmation gate, execute, draft PR body with
confirmation gate, raise PR), plus rules for branch prefixes (binary
feat/vsfix/), commit grouping, secrets scanning, and PR-sectionsource mapping.
pr-body-template.mdis the canonical PR body template the skillreads on every run, so future structural changes to PR descriptions
are made by editing the template alone.
Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)
No runtime impact. The change is purely additive Claude Code tooling
under
.claude/skills/— no application code, build config, CIworkflow, or product surface is touched. The skill is gated behind
manual
/shipinvocation, so it cannot auto-trigger.Database Migrations
None.
Env Config
None.
Relevant Docs
None.
Related Issues or PRs
None.
Dependencies Versions
None.
Notes on Testing
/shipon a clean working tree onmainand confirm it stops with a clear "no changes" message/shipwith mixed feat + fix changes and confirm it asks whether to split before proceeding/shipwith a staged file containing a fakesk-…token and confirm the secrets-scan hard-stop fires before any commit/shipend-to-end on a small change and confirm the draft PR is opened with the body sourced frompr-body-template.md(not.github/)--no-verifyretry and no amenddisable-model-invocation: truehonoured)Screenshots
N/A — tooling-only change, no UI surface.
Checklist
I have read and understood the Contribution Guidelines.